#pragma once
#include <core/container/LinkedHashMap.h>
#include <core/container/SHash.h>
#include <core/strings/TinyString.h>
#include <map>
#include <string>
#include "bondlib.h"
/*
	[内存优化][scofined.qi]
	BondContainer中以数组的形式保存市场上全部债券的信息,每支债券都有一个
	唯一的主键CombBondKey,即CBondInfoImpl.m_sCombBondKey
	为了快速通过主键来搜索债券,CBondContainer中用容器m_keymap来保持
	从主键CombBondKey到数组索引的映射
	当前文件就是这个容器的内存优化的改进实现

	绝大部分债券主键是存在严格编码规律的,BondCodeCompact就是从编码规律中
	提取的结构体,BondKeyParser用来从字符串形式的债券主键解码成BondCodeCompact,
	以便很好的在从BondCodeCompact到int的哈希映射中快速查找

	债券代码也是类似的,BondCodeCompact表示从编码规律提取的结构体
	BondCodeParser是如何从字符串形式的债券代码解析到BondCodeCompact

	少量无规律,无法用BondCodeCompact编码的债券主键,则以
	std::map<kstring, BondIndex> m_backupmap的形式存在,只占2k左右
	BondCodeCompact中,将债券索引先定位6+16个比特位,即最大支持4194304
	足够支撑现有债券发展趋势

	使用新的容器的好处:
	1.编码内存少:只需要10个字节,就能描述主键key和债券索引的信息
	2.占用内存少:原先哈希表一个节点只能放一个键值,节点中元信息内存比例较高
				 新容器中,一个节点至多放16个键值,节点中源信息内存比例较低
	3.内存碎片少:所有节点都是固定大小
	4.缓存行友好:哈希碰撞的所有主键都放在一个节点中,落在紧凑的缓存行中
	5.并行搜索  :在一个节点中,使用硬加速的并行搜索指令进行快速过滤

	简单的说,就是内存少,碎片少,性能快
	要注意的是:
		1.债券总数量限定为2^22个
		2.债券主键绝大部分符合提取的编码规律
		3.经过测试,该哈希表的哈希插槽数组长度为2^13,性能和内存综合最好
			因此BondKeyMapImpl中,Expand的参数为13,表示长度为2^13
*/
typedef intptr_t BondIndex;
typedef unsigned int uint;
typedef int64_t i64;
#pragma pack(push) 
#pragma   pack(2) 

#ifdef WIN32
#define KEY_ALIGN __declspec(align(1))
#else
#define KEY_ALIGN __attribute__((aligned(1)))
#endif
struct KEY_ALIGN ComBondKeyCompact{		// 将债权键解析出每个字段
	
	enum{
		LowBitMask = (1 << 26) - 1,
		HashSize = sizeof(uint) + sizeof(uint),
		kInvalidHead = 0,		// 0表示bkey的head空值
	};
	struct First{
		uint	id : 16;	// 最大值:1706
		uint	seq : 14;	// 最大值:10302
		uint	nzero : 2;	// 2位,
	};
	struct Second{
		uint	head : 5;	// 5bit,A-Z,如果是小写都转化为大写
		uint	year : 5;	// 32年,从2000开始
		uint	market : 5;	// 5bit,总共有6种,支持32种
		uint	type : 5;	// 4bit,总共有12中,支持64
		uint	sub : 6;	// 6bit,总共有38种,支持64
		uint	hibid : 6;	//
	};
	union {
		First	first;
		uint	ufirst;
	};
	union{
		Second	second;
		uint	usecond;
	};
	unsigned short	bid;		// 
public:
	ComBondKeyCompact(){
		Clear();
		static_assert(sizeof(ComBondKeyCompact) == 10, "sizeof(ComBondKeyCompact)");
	}
	void Clear(){ memset(this, 0, sizeof(*this)); }
	bool IsEmpty()const{ return second.head == kInvalidHead; };
	unsigned int GetHash()const{
		// 要求hibid必须为0
		return qb::base::murMurHash((const char*)this, HashSize);
	}
	bool EqualKey(const ComBondKeyCompact& key)const{
		// 忽略key的bid和hibid,检查两个结构体是否相同
		// 可以考虑用加速函数如_mm_cmpeq_epi8 
		return ufirst == key.ufirst && (usecond&LowBitMask) == (key.usecond&LowBitMask);
	};
	int GetValue()const{ return ((uint)second.hibid) << 16 | ((uint)bid); }
	void SetValue(const BondIndex& value){
		bid = ((unsigned int)value & 0x0000ffff);
		second.hibid = ((unsigned int)value) >> 16;
	};
	bool operator<(const ComBondKeyCompact& key)const{
		if (second.year == key.second.year)
			return *((i64*)this) < *((i64*)&key);
		return second.year < key.second.year;
	}
};
#pragma pack(pop)

struct BondCodeCompact{//总共也是10个字节
	enum{ LOW_MASK = 0x000003FF };
	struct First{
		unsigned int	id : 22;
		unsigned int	code : 5;		// A-Z 26个字符,0表示没有
		unsigned int	seq : 5;		// 不超过32的两位小数,不能以0开头,不能是0
	};
	struct Second{
		unsigned short	flag : 1;		// 0表示纯数字模式,1表示混合模式
		unsigned short	zero : 3;		// 最前面有几个数字0
		unsigned short	market : 6;		// .IB,.SH,.SZ等
		unsigned short	hibid : 6;		// 
		unsigned short	bid;			// 共22位
	};
	union{
		First			first;			// 当flag为0时取这个,表示有code和seq区分
		unsigned int	id;				// 当flag为1时取这个,表示纯数字
	};
	union{
		Second			second;
		unsigned int	index;
	};
	BondCodeCompact(){
		Clear();
		static_assert(sizeof(BondCodeCompact) == 8, "sizeof(ComBondKeyCompact)");
	}
	void Clear(){ id = 0; index = 0; }
	bool IsEmpty()const{ return id == 0; };
	unsigned int GetHash()const{
		// 要求hibid必须为0
		BondCodeCompact info; info.id = id; info.index = index; info.second.bid = 0; info.second.hibid = 0;
		return qb::base::murMurHash((const char*)&info, sizeof(BondCodeCompact));
	}
	bool EqualKey(const BondCodeCompact& key)const{
		// 忽略key的bid和hibid,检查两个结构体是否相同
		// 可以考虑用加速函数如_mm_cmpeq_epi8 
		return second.flag == key.second.flag &&
			second.zero == key.second.zero &&
			id == key.id && second.market == key.second.market;
	};
	int GetValue()const{ return ((uint)second.hibid) << 16 | ((uint)second.bid); }
	void SetValue(const BondIndex& value){
		second.bid = ((unsigned int)value & 0x0000ffff);
		second.hibid = ((unsigned int)value) >> 16;
	};
	bool operator<(const BondCodeCompact& key)const{
		if (id == key.id){ return (index&LOW_MASK) < (key.index&LOW_MASK); }
		return id < key.id;
	}
};
struct CodeId{
	union{
		char	code[4];
		int		id;
	};
public:
	CodeId(const char* str) :id(0){ code[0] = str[0]; code[1] = str[1]; code[2] = str[2]; code[3] = '\0'; }
	CodeId(int d) :id(d){}
	inline bool operator<(const CodeId& ci)const{ return id < ci.id; }
	inline bool EqualTo(const char* str)const{
		return code[0] == str[0] && code[1] == str[1] && code[2] == str[2];
	}
};
class NameDict {
	// 后续可以考虑用哈希表实现
	struct CodeIdInfo{
		CodeId		code;
		int			index;
	public:
		CodeIdInfo(const char* str) :code(str), index(0){}
		CodeIdInfo() :index(0), code(0){}
		void Clear(){ index = -1, code = CodeId(0); }
		bool IsEmpty()const{ return index < 0; };
		unsigned int GetHash()const{ return code.id; }
		bool EqualKey(const CodeIdInfo& key)const{ return code.id == key.code.id; };
		const int& GetValue()const{ return index; }
		void SetValue(const int& value){ index = value; };
	};
	typedef qb::base::LinkedHashMap<CodeIdInfo, int> CodeDict;
	CodeDict				m_dict;
	CodeIdInfo**			m_array;
	int						m_capcity;
	int						m_count;
public:
	NameDict(int capcity = 100) :m_dict(capcity), m_count(0){
		m_array = new CodeIdInfo*[capcity];
		memset(m_array, 0, capcity*sizeof(CodeIdInfo*));
	}
	~NameDict(){}
	int GetCount()const{ return m_dict.GetCount(); }
	int GetBytes()const{
		return m_dict.GetBytes();
	}
	int Add(const char* str)
	{
		CodeIdInfo info(str);
		if (m_dict.Get(info, info.index))
			return info.index;
		int index = m_count;
		m_dict.Put(info, index);
		m_count++;
		return index;
	}
};

class S_BONDLIB_EXPORT NameDictHash {
	// 后续可以考虑用哈希表实现
	struct NodeInfo{
		CodeId		code;
		int			index;
		NodeInfo*	next;
		NodeInfo(NodeInfo* n, int i, const CodeId& ci) :index(i), next(n), code(ci.id){}
		NodeInfo(NodeInfo* n, int i, const char* str) :index(i), next(n), code(str){}
	};
	NodeInfo**			m_array;
	//map<CodeId, int>	m_codes;
	int					m_capcity;
	int					m_bitcount;
	int					m_count;
public:
	NameDictHash(int capcity = 4, const char* str = nullptr);
	~NameDictHash();
	void Init(const char* str);
	int GetCount()const{ return m_count; }
	int GetBytes()const{
		return m_count*sizeof(NodeInfo) + sizeof(*this);
	}
	int Add(int id);
	int Add(const char* str);
};
typedef NameDictHash DictType;


class S_BONDLIB_EXPORT BondKeyParser{
	typedef ComBondKeyCompact ComBondKey;
	DictType	m_types;		// 12,4bit
	DictType	m_subs;			// 38,6bit
	DictType	m_markets;		// 6,3bit
public:
	BondKeyParser();
	bool Parse(const char* str, int len, ComBondKey& key);
	bool IsAlpha(char c)const
	{
		return (c >= 'a'&&c <= 'z') || (c >= 'A'&&c <= 'Z');
	}

	int ToInt(const char* str, int pos, int len)
	{
		int num = 0;
		const char* ptr = str + pos;
		const char* end = ptr + len;
		while (ptr < end)
		{
			num = (num << 3) + (num << 1) + (*ptr++ - '0');
		}
		return num;
	}
	int GetIntLength(const char* str, int len)const;
	int GetTypeRange(const char* str, int len, int& end);
};
class S_BONDLIB_EXPORT BondCodeParser{
	enum{
		MaxSeq = 31,		// 2^5-1
		MaxCode= 26,		// 0,'A'对应编码1,'B'对应编码2,'C'对应编码3,...'Z'对应编码26
		MaxZero=7,			// 最前面'0'的最大个数为7,只有3个编码位
		MaxShortId=1<<22,	// 22个比特位表示
	};
	DictType	m_markets;		// 6,3bit
public:
	BondCodeParser();
	bool Parse(const char* str, int len, BondCodeCompact& code);
	int TestNum(const char* str, int len,int& number)
	{
		int i = 0;
		number = 0;
		for (; i < len; i++)
		{
			if (str[i] < '0' || str[i]>'9')
				break;
			number = number * 10 + (str[i] - '0');
		}
		return i;
	}
	int TestZero(const char* str, int len)
	{
		int i = 0;
		for (; i < len; i++)
		{
			if (str[i] != '0')
				break;
		}
		return i;		
	}
};
template<
	typename EntryType,
	typename KeyParser,
	typename CacheLine = qb::base::F14LinkedChunk<EntryType, BondIndex >
>
class BondKeyHashMap{					// 专门用于债券组合键的哈希表
	typedef unsigned short ushort;
	typedef unsigned int uint;
	typedef int64_t i64;

	static_assert(sizeof(i64) == 8, "");
	typedef qb::base::TinyString KeyType;//比KeyString,在查找的时候,减少一次内存分配
	typedef std::map<KeyType, BondIndex>  IndexMap;
	// 示例值:G0001242014ABSAMP0801.CIB
	// 假设:不存在G124的发行人编号


public:
	enum{
		kMaxBondId = 1 << 22,	// 400w债券,这个值和kYearBase根bkey中的year占的位个数有关
	};
	struct ComBondKeyBig{		// 将债权键解析出每个字段
		char	head;		// 第一个字母,表示发行人编号的字母
		char	type;		// 
		char	sub;		//
		char	market;		// 
		ushort	id;			// 发行人编号数字
		ushort	nzero : 2;	// 编号,高2bit表示前面有0的个数,最大支持4个
		ushort	seq : 14;		// 编号,低0-14位,表示转化的整数,最大值为16384
		ushort	year : 10;	// 表示年份
		ushort	hibid : 6;	// 额外6个bit表示bondindex,总共22个,支持400w
		ushort	bid;		// bond index,bid不参与hash计算
	public:
		ComBondKeyBig(){ Clear(); }
		inline void Clear(){ memset(this, 0, sizeof(*this)); }
		inline bool IsEmpty()const{ return head == ComBondKeyCompact::kInvalidHead; };
		inline unsigned int GetHash()const{
			//TODO: security in x64?
			return qb::base::murMurHash((const char*)this, sizeof(ComBondKeyBig) - sizeof(ushort));
		}
		inline bool EqualKey(const ComBondKeyBig& key)const{
			// 忽略key的bid和hibid,检查两个结构体是否相同
			// 可以考虑用加速函数如_mm_cmpeq_epi8  
			return *((i64*)this) == *((i64*)&key) && year == key.year;
		};
		inline int GetValue()const{ return ((uint)hibid) << 16 | ((uint)bid); }
		inline void SetValue(const BondIndex& value){
			bid = ((unsigned int)value & 0x0000ffff);
			hibid = ((unsigned int)value) >> 16;
		};
		inline bool operator<(const ComBondKeyBig& key)const{
			if (year == key.year)return *((i64*)this) < *((i64*)&key);
			return year < key.year;
		}
	};
	//typedef qb::base::HighResTime HighResTime;
	typedef EntryType ComBondKey;
	typedef qb::base::LinkedHashMap<ComBondKey, BondIndex, CacheLine> BondKeyMap;
	//typedef LinkedHashMap<ComBondKey, BondIndex, CacheLineArray<ComBondKey, BondIndex>> BondKeyMap;
private:
	KeyParser	m_parser;
	BondKeyMap	m_bondkeys;		// 
	IndexMap	m_backupmap;	// 备用表,适合解析失败的bondkey
	double		m_update;		// 
public:
	BondKeyHashMap() :
		m_bondkeys(),
		m_update(0)
	{
		
	}
	~BondKeyHashMap()
	{
	}
	void RemoveAll()
	{
		m_backupmap.clear();
		BondKeyMap temp(m_bondkeys.GetBitCount());
		m_bondkeys.Swap(temp);
	}
	BondIndex GetBondIndex(const char* comBondKey, int len)
	{
		ComBondKey key;
		if (m_parser.Parse(comBondKey, len, key) && !key.IsEmpty())
		{
			BondIndex bid = -1;
			if (m_bondkeys.Get(key, bid))
				return bid;
		}
		else
		{
			auto it = m_backupmap.find(qb::base::TempTinyString(comBondKey));
			if (it != m_backupmap.end())
				return it->second;
		}
		return -1;
	}
	void AddBondKey(const char* comBondKey, int len, BondIndex bid)
	{
		ComBondKey key;
		//HighResTime timer;
		if (m_parser.Parse(comBondKey, len, key) && !key.IsEmpty() && bid<kMaxBondId)
			m_bondkeys.Put(key, bid);
		else
			m_backupmap.emplace(KeyType(comBondKey, len), bid);
		//m_update += timer.elapsed();
	}
	bool EraseBondKey(const char* comBondKey, int len)
	{
		ComBondKey key;
		if (m_parser.Parse(comBondKey, len, key) && !key.IsEmpty())
			return m_bondkeys.Erase(key);
		else
		{
			auto it = m_backupmap.find(KeyType(comBondKey, len));
			if (it != m_backupmap.end())
			{
				m_backupmap.erase(it);
				return true;
			}
		}
		return true;
	}
	void Expand(int capBits)
	{
		m_bondkeys.Expand(capBits);
	}
	int GetCount()const{ return m_bondkeys.GetCount()+m_backupmap.size(); }
	int GetLength()const{ return m_bondkeys.GetCount() + m_backupmap.size(); }
	int GetBytes()const{
		qb::base::LinkedHashMapStat stat;
		m_bondkeys.GetStat(stat);
		return stat.bytes;
	}
	double GetLoadRatio()const{ return m_bondkeys.GetLoadRatio(); }
public://接口适配
	void emplace(const std::string& str, int bid){
		AddBondKey(str.c_str(), str.size(), bid);
	}
	class iterator{
		int		m_bondid;
	public:
		iterator(int bid = -1) :m_bondid(bid){}
		bool operator==(const iterator& it){ return false; }
	};
	iterator find(const std::string& str){
		return GetBondIndex(str.c_str(), str.size());
	}
	iterator end()const{ return iterator(); }
public://调试支持接口
	void Dump()
	{
	}
};
